// Copyright © SixtyFPS GmbH <info@slint.dev>
// SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-Slint-Royalty-free-2.0 OR LicenseRef-Slint-Software-3.0

import { Preview } from "./color-basics.slint";

import { Api, BrushKind, GradientStop } from "../../api.slint";

component GradientDot inherits Rectangle {
    in-out property <bool> selected: false;
    out property <bool> has-hover <=> ta.has-hover;

    in property <length> parent-width;
    in-out property <[GradientStop]> gradient-stops;
    in property <int> index;

    in property <int> apply-update;

    x: parent-width * self.gradient-stops[self.index].position - self.width / 2.0;

    callback select-gradient-stop();
    callback unselect-gradient-stop();
    callback update-brush();

    width: self.selected ? 20px : 10px;
    height: self.selected ? 20px : 10px;
    border-radius: self.width;
    background: root.gradient-stops[root.index].color;
    border-width: root.selected ? 2px : 1px;
    border-color: root.selected ? black : gray;
    Rectangle {
        border-radius: self.width;
        border-color: root.selected ? white : white.transparentize(0.5);
        border-width: 1px;
    }

    ta := TouchArea {
        private property <length> x-pos: self.mouse-x + root.x;

        changed has-hover => {
            if !root.selected && self.has-hover {
                root.select-gradient-stop();
            }
        }

        double-clicked => {
            Api.remove-gradient-stop(root.gradient-stops, index);
            root.update-brush();
        }

        moved => {
            root.gradient-stops[root.index].position = Math.clamp(self.x-pos, 0, root.parent-width) / root.parent-width;
            root.update-brush();
        }

        scroll-event(event) => {
            if event.delta-y != 0 {
                root.gradient-stops[root.index].position = Math.clamp(
                    root.gradient-stops[root.index].position + Math.clamp((event.delta-y / 1px), -0.01, +0.01),
                    0.0, 1.0);
                root.update-brush();

                return EventResult.accept;
            }
            return EventResult.reject;
        }
    }
}

export component GradientMainContent inherits HorizontalLayout {
    in property <brush> current-brush;
    in property <BrushKind> current-brush-kind;

    in-out property <[GradientStop]> gradient-stops;
    in-out property <float> current-position;
    private property <float> current-position_: index-position(self.selected-index);

    in-out property <color> current-color;
    private property <color> current-color_: index-color(self.selected-index);

    out property <bool> has-focus: ta.has-hover || self.dot-hover-count > 0;
    out property <int> selected-index: -1;

    callback update-brush();

    private property <int> apply-update-to: -1;

    changed current-color_ => {
        self.current-color = current-color_;
    }

    changed current-color => {
        if self.selected-index >= 0 && self.selected-index < self.gradient-stops.length {
            self.gradient-stops[self.selected-index].color = current-color;
        }
        apply-model-change-to-ui();
    }

    changed current-position_ => {
        self.current-position = current-position_;
    }

    changed current-position => {
        if self.selected-index >= 0 && self.selected-index < self.gradient-stops.length {
            self.gradient-stops[self.selected-index].position = current-position;
        }
        apply-model-change-to-ui();
    }

    pure function index-color(index: int) -> color {
        if index >= 0 && index < self.gradient-stops.length {
            return self.gradient-stops[index].color;
        }
        return Colors.transparent;
    }

    pure function index-position(index: int) -> float {
        if index >= 0 && index < self.gradient-stops.length {
            return self.gradient-stops[index].position;
        }
        return 0.0;
    }

    function apply-model-change-to-ui() {
        if self.selected-index >= 0 {
            self.apply-update-to = self.selected-index;
        }
    }

    function apply-gradient-stops() {
        if (self.selected-index < 0) || (self.selected-index >= self.gradient-stops.length) {
            if self.gradient-stops.length > 0 {
                self.selected-index = 0;
            } else {
                self.selected-index = -1;
            }
        }
    }

    init => {
        apply-gradient-stops();
    }

    changed gradient-stops => {
        apply-gradient-stops();
    }

    private property <int> dot-hover-count: 0;

    grad := Preview {
        width: 100%;
        height: 40px;

        if (current-brush-kind == BrushKind.radial): Rectangle {
            width: parent.width * 2;
            x: 0 - parent.width;

            background: root.current-brush;
        }

        background: current-brush-kind == BrushKind.radial ? transparent : root.current-brush;

        ta := TouchArea {
            double-clicked => {
                root.selected-index = Api.add-gradient-stop(root.gradient-stops, Api.suggest-gradient-stop-at-position(root.gradient-stops, self.mouse-x / self.width));

                root.update-brush();
            }

            scroll-event(event) => {
                if event.delta-y != 0 && root.selected-index >= 0 {
                    root.gradient-stops[root.selected-index].position = Math.clamp(
                        root.index-position(root.selected-index) + Math.clamp((event.delta-y / 1px), -0.01, +0.01),
                        0.0, 1.0);
                    root.update-brush();

                    root.apply-update-to = root.selected-index;

                    return EventResult.accept;
                }
                return EventResult.reject;
            }
        }

        Rectangle {
            height: 1px;
            background: grey;

            for i[index] in root.gradient-stops: GradientDot {
                selected: root.selected-index == index;
                gradient-stops <=> root.gradient-stops;
                index: index;

                changed has-hover => {
                    if self.has-hover {
                        root.dot-hover-count += 1;
                    } else {
                        root.dot-hover-count -= 1;
                    }
                }

                parent-width: grad.width;

                select-gradient-stop() => {
                    root.selected-index = index;
                }

                update-brush() => {
                    root.update-brush();
                }
            }
        }
    }
}
